package GA;

import java.util.Arrays;

import Operations.ValuesGenerator;


import mutation.Mutation;
import crossover.Crossover;
import random.TestClusterBuilder;
import util.*;
import selection.*;

public class Population {
	private static final int POPULATION_SIZE    = GAConfig.PopulationSize;
	public static Chromosome[] randomPopulationInitializer(TestClusterBuilder TestCluster) {		
		Chromosome[] population = new Chromosome[POPULATION_SIZE];
		//Generate random population
		for(int individual = 0; individual < POPULATION_SIZE; individual++) {
			population[individual]=ChromosomeFormer.buildNewChromosome(TestCluster);
		}
		
		return population;
	}
	public static Chromosome[] generateNewPopulation(GAInfo gaInfo,TestClusterBuilder TestCluster) {
        Selection parentSelector = GAOperationsConfig.getParentSelector();
        Crossover crossoverStrategy = GAOperationsConfig.getCrossoverStrategy();
        parentSelector.setExtraInfo(gaInfo);
        Chromosome[] newPopulation = new Chromosome[POPULATION_SIZE];
        Chromosome[] population = gaInfo.getPopulation();
   //     int elitismNum=GAConfig.elitismNumBest;
        int elitismNum=(int)(((double)GAConfig.PopulationSize/(double)100) * GAConfig.elitismNumBest); 
 //       for (int i = elitismNum,j=elitismNum; i <= (POPULATION_SIZE / 2); i++) {
        for (int j=elitismNum; j < POPULATION_SIZE ;) {
                int parent_Indx_1=parentSelector.selectTwoParents();
                int parent_Indx_2=parentSelector.selectTwoParents();
                if(GAConfig.Debug)Log.log("parent_Indx_1: "+ parent_Indx_1+ "parent_Indx_2: "+ parent_Indx_2+"\n"); 
                Chromosome parent1=gaInfo.getPopulation()[parent_Indx_1].clone();
                Chromosome parent2=gaInfo.getPopulation()[parent_Indx_2].clone();
                if(GAConfig.Debug)Log.log("parent1: "+parent1.toString());
                if(GAConfig.Debug)Log.log("parent2: "+parent2.toString());
                //Get the two children
                Chromosome[] offspring = crossoverStrategy.crossOver(parent1, parent2);


                mutateChromosome(offspring[0],TestCluster);
                mutateChromosome(offspring[1],TestCluster);
                
                if(GAConfig.Debug)Log.log("offspring1: "+offspring[0].toString());
                if(GAConfig.Debug)Log.log("offspring2: "+offspring[1].toString());
                
                newPopulation[j++]=offspring[0];
                newPopulation[j++]=offspring[1];
        }
        //Order initial population based on fitness
        Arrays.sort(population);
        for(int i=0; i<GAConfig.elitismNumBest;i++){
                if(GAConfig.Debug)Log.log("elitismNumBest" + i +": "+population[i].toString());
                newPopulation[i]= population[i];
        }

        return newPopulation;
        
	}
	private static void mutateChromosome(Chromosome offspring,TestClusterBuilder TestCluster) {
		Mutation ChangeValueStrategy = GAOperationsConfig.getMutationChangeValueStrategy();
		Mutation MethodInsertStrategy = GAOperationsConfig.getMutationMethodInsertStrategy();
		Mutation MethodDeleteStrategy = GAOperationsConfig.getMutationMethodDeleteStrategy();

		MethodInsertStrategy.setExtraInfo(TestCluster);
		MethodDeleteStrategy.setExtraInfo(TestCluster);
		try {
			int ran = ValuesGenerator.getRandomIntBetween(1,90);
			if (ran <= 30) {
				// changeInputValue();
				ChangeValueStrategy.mutateChromosome(offspring);
			} else if (ran <= 60) {
				// insert Related/Random Method Call();
				MethodInsertStrategy.mutateChromosome(offspring);
			}else if (ran <= 90) {
				// insert Related/Random Method Call();
				MethodDeleteStrategy.mutateChromosome(offspring);
			}
		} catch (Throwable e) {
			System.err.println("Population.mutateChromosome: " + e);
			System.exit(1);
		}

	}

	public static String toString(GAInfo gaInfo) {
		StringBuilder population = new StringBuilder();
		population.append("\t\t Generation "+ gaInfo.getGeneration() +"\n");
		for(Chromosome individual : gaInfo.getPopulation()) {
			System.out.println("population.toString : "+individual.toString());
			population.append(individual.toString()+ "\n");
		}
		return "";//population.toString();
	}

}
